// import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem_ptr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.ArrayList;
// import java.util.List;

#include "SQLZOrderBy.h"
#include "../visitor/SQLASTVisitor.h"
#include "statement/SQLSelectOrderByItem.h"
#include "../../utils/ifeq.h"

SQLZOrderBy::SQLZOrderBy()
{
  items = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
}

SQLZOrderBy::SQLZOrderBy(SQLExpr_ptr expr)
{
  SQLSelectOrderByItem_ptr item = SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem(expr));
  addItem(item);
}

SQLZOrderBy::SQLZOrderBy(SQLExpr_ptr expr, SQLOrderingSpecification_ptr type)
{
  SQLSelectOrderByItem_ptr item = SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem(expr, type));
  addItem(item);
}

void SQLZOrderBy::addItem(SQLSelectOrderByItem_ptr item)
{
  if (item != nullptr)
  {
    item->setParent(SharedObject(SQLZOrderBy));
  }
  this->items->push_back(item);
}

void SQLZOrderBy::addItem(SQLExpr_ptr item)
{
  addItem(SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem(item)));
}

SQLSelectOrderByItem_list_ptr SQLZOrderBy::getItems()
{
  return this->items;
}

BOOL_ptr SQLZOrderBy::isSibings()
{
  return this->sibings;
}

void SQLZOrderBy::setSibings(BOOL_ptr sibings)
{
  this->sibings = sibings;
}

void SQLZOrderBy::accept0(SQLASTVisitor_ptr v)
{
  if (v->visit(SharedObject(SQLZOrderBy)))
  {
    auto it_items = this->items->begin();
    for (int i = 0; i < this->items->size(); i++)
    {
      std::advance(it_items, i);
      SQLSelectOrderByItem_ptr item = *it_items;
      item->accept(v);
    }
  }

  v->endVisit(SharedObject(SQLZOrderBy));
}

// @Override
bool SQLZOrderBy::equals(Object_ptr o)
{
  if (this == o.get())
  {
    return true;
  }
  if (o == nullptr || getClass() != o->getClass())
  {
    return false;
  }

  SQLZOrderBy_ptr order = std::dynamic_pointer_cast<SQLZOrderBy>(o);

  if (sibings != order->sibings)
  {
    return false;
  }
  return IFEQ::ifeq<SQLSelectOrderByItem_ptr>(items, order->items);
}

// @Override
int SQLZOrderBy::hashCode()
{
  // int result = items->hashCode();
  int result = 1;
  result = 31 * result + (sibings ? 1 : 0);
  return result;
}

void SQLZOrderBy::addItem(SQLExpr_ptr expr, SQLOrderingSpecification_ptr type)
{
  SQLSelectOrderByItem_ptr item = createItem();
  item->setExpr(expr);
  item->setType(type);
  addItem(item);
}

// @Override
BOOL_ptr SQLZOrderBy::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  for (SQLSelectOrderByItem_ptr item : *items)
  {
    if (item->replace(expr, target))
    {
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

SQLSelectOrderByItem_ptr SQLZOrderBy::createItem()
{
  return SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem());
}

SQLObject_ptr SQLZOrderBy::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLZOrderBy>(new SQLZOrderBy());
  std::shared_ptr<SQLZOrderBy> x = std::dynamic_pointer_cast<SQLZOrderBy>(clone_tmp);
  // SQLZOrderBy x = new SQLZOrderBy();

  for (SQLSelectOrderByItem_ptr item : *items)
  {
    SQLSelectOrderByItem_ptr item1 = std::dynamic_pointer_cast<SQLSelectOrderByItem>(item->clone());
    item1->setParent(x);
    x->items->push_back(item1);
  }

  x->sibings = sibings;

  return x;
}
